package com.huangmingfu;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: 黄名富
 * @Description: 解释器模式
 * @CreationDate: 2024/6/2
 * @需求描述: 对整数简单的计算文本，计算出结果。 加减乘除及括号
 */
public class InterpreterPattern {
    /**
     * 语法规则：
     * value ::= a integer
     * operator ::= '+' | '-' | '*' | '/'
     * expression ::= value operator value | complexExpression
     * complexExpression ::= expression operator expression | expression operator (expression)
     */

    public static void main(String[] args) {
        String[] textArr = {"1+4*3","4*5+3","(3+4)*23", "(3+24)-(23-8)", "(2-3)*(24+2*3)", "(((1+2)*(2+3)))+32"};
        for (int i = 0; i < textArr.length; i++) {
            System.out.print(textArr[i]);
            System.out.println("=" + new ComplexExpression().interpreter(textArr[i]));
        }
    }

    private static abstract class Expression {
        abstract int interpreter(String text);

        protected int compute(int leftNum,int rightNum,char opera) {
            switch (opera) {
                case '+': return leftNum + rightNum;
                case '-': return leftNum - rightNum;
                case '*': return leftNum * rightNum;
                case '/': return leftNum / rightNum;
            }
            return 0;
        }
    }

    /**
     * 复杂表达式
     */
    private static class ComplexExpression extends Expression {
        @Override
        int interpreter(String text) {
//            System.out.println("ComplexExpression:" + text);
            int letNum=0;
            int rightNum=0;
            char opera = ' ';

            Pattern pattern = Pattern.compile("[\\+\\-\\*\\/]");
            Matcher matcher = pattern.matcher(text);
            if (matcher.find()) {
                int start = matcher.start();
                opera = text.charAt(start);
                if (text.indexOf("(") == 0) { // 在操作符前面有括号, 先计算括号的内容
                    int endBracketPos = findEndBracketPos(text);
                    letNum = new ComplexExpression().interpreter(text.substring(1,endBracketPos));
                    if (endBracketPos == text.length() -1 ) {
                        return letNum;
                    }
                    opera = text.charAt(endBracketPos+1);
                    rightNum = new ComplexExpression().interpreter(text.substring(endBracketPos+2));
                } else if ((opera == '*' || opera == '/') && text.charAt(start+1) != '(') { // 需要先完成左边运算
                    boolean hasNext = matcher.find(start + 1);
                    if (hasNext) {
                        int pos2 = matcher.start();
                        letNum = new ComplexExpression().interpreter(text.substring(0,pos2));
                        opera = text.charAt(pos2);
                        rightNum = new ComplexExpression().interpreter(text.substring(pos2+1));
                    } else {
                        letNum = new TerminalExpression().interpreter(text.substring(0,start));
                        rightNum = new ComplexExpression().interpreter(text.substring(start+1));
                    }

                } else {
                    letNum = new TerminalExpression().interpreter(text.substring(0,start));
                    rightNum = new ComplexExpression().interpreter(text.substring(start+1));
                }
                return compute(letNum,rightNum,opera);
            } else { // 终结表达式
                return new TerminalExpression().interpreter(text);
            }
        }

        private int findEndBracketPos(String text) {
            int startPos = 0,endPos = 0;
            do {
                endPos = text.indexOf(")",endPos+1);
                startPos = text.indexOf("(",startPos+1);
            } while (startPos < endPos && startPos > 0);
            return endPos;
        }

    }

    /**
     * 是一个数值 或者 是 (数值) 形式，要把text 转换为数值
     */
    private static class TerminalExpression extends Expression {
        @Override
        int interpreter(String text) {
//            System.out.println("TerminalExpression:" + text);
            if (text.indexOf("(") == 0) {
                text = text.substring(1,text.length() - 1);
            }
            return Integer.parseInt(text);
        }
    }

}
